package com.etlmaster.executor.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;

import com.etlmaster.executor.utils.LogWriter;

public abstract class Shell {

	public static class ShellCommandExecutor extends Shell {
		private final String[] command;
		private StringBuffer output;

		public ShellCommandExecutor(String[] execString) {
			command = execString.clone();
		}

		public ShellCommandExecutor(String[] execString, File dir) {
			this(execString);
			this.setWorkingDirectory(dir);
		}

		public ShellCommandExecutor(String[] execString, File dir, Map<String, String> env) {
			this(execString, dir);
			this.setEnvironment(env);
		}

		public void execute() throws IOException {
			this.run();
		}

		public String getOutput() {
			return (output == null) ? "" : output.toString();
		}

		@Override
		protected String[] getExecString() {
			return command;
		}

		@Override
		protected void parseExecResult(BufferedReader lines) throws IOException {
			output = new StringBuffer();
			char[] buf = new char[10240];
			int nRead;
			while ((nRead = lines.read(buf, 0, buf.length)) > 0) {
				output.append(buf, 0, nRead);
				//output.append("\n");
			}
		}
	}

	static class ExitCodeException extends IOException {

		private static final long serialVersionUID = -7102633161419484030L;

		int exitCode;

		public ExitCodeException(int exitCode, String message) {
			super(message);
			this.exitCode = exitCode;
		}

		public int getExitCode() {
			return exitCode;
		}
	}

	public static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows");

	public static String execCommand(Map<String, String> env, String... cmd) throws IOException {
		ShellCommandExecutor exec = new ShellCommandExecutor(cmd);
		if (env != null) {
			exec.setEnvironment(env);
		}
		exec.execute();
		return exec.getOutput();
	}
	
	

	public static String execCommand(String... cmd) throws IOException {
		return execCommand(null, cmd);
	}
	


	private Map<String, String> environment;

	private File dir;

	private Process process;

	private int exitCode;

	public int getExitCode() {
		return exitCode;
	}

	public Process getProcess() {
		return process;
	}

	protected abstract String[] getExecString();

	protected abstract void parseExecResult(BufferedReader lines) throws IOException;

	protected void run() throws IOException {
		exitCode = 0; //reset
		runCommand();
	}

	protected void setEnvironment(Map<String, String> env) {
		this.environment = env;
	}

	protected void setWorkingDirectory(File dir) {
		this.dir = dir;
	}
	
	public String runCmdLog(String command){
		String []cmd = new String[3];
		cmd[0]="sh";
		cmd[1]="-c";
		cmd[2]=command;
		StringBuffer sb=new StringBuffer();
		//new TelnetProcessor().execute(cmd);
		Process child = null;
		try {
		 
			Runtime rt = Runtime.getRuntime();
			child = rt.exec(cmd);
			
			// 以下代码为控制台输出相关的批出理
			String line = null;
			BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream(),"UTF-8"));
			
			//parseExecResult(reader);
			
			while ((line = reader.readLine()) != null) {
				//System.out.println(line);
				LogWriter.addLog("INFO",line);
				sb.append(line);
				//errMsg.append(line);
				//errMsg.append(System.getProperty("line.separator"));
			};
			
			reader.close();
			 
			exitCode=child.waitFor();
		} catch (Exception ex) {
			//System.out.println(ex.getMessage());
			LogWriter.addLog("ERROR",ex.getMessage());
			child.destroy();
		}
		return sb.toString();
}
	
	public void runCmd(String command){
		String cmd = "date|awk '{print $2,$3,$4}'";
		//new TelnetProcessor().execute(cmd);
		Process child = null;
		try {
		 
			Runtime rt = Runtime.getRuntime();
			child = rt.exec(command);
			// 以下代码为控制台输出相关的批出理
			String line = null;
			
			int readLine = 0;
			int loadLine = -1;
			int commitLine = -1;
			final StringBuffer errMsg = new StringBuffer();
			BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream(),"GBK"));
			
			parseExecResult(reader);
			/*
			while ((line = reader.readLine()) != null) {
				System.out.println(line);
				
				errMsg.append(line);
				errMsg.append(System.getProperty("line.separator"));
			};
			*/
			reader.close();
			 
			exitCode=child.waitFor();
		} catch (Exception ex) {
			//System.out.println(ex.getMessage());
			LogWriter.addLog("ERROR",ex.getMessage());
			child.destroy();
		}
}
	private void runCommand() throws IOException {
		ProcessBuilder builder = new ProcessBuilder(getExecString());
		boolean completed = false;

		if (environment != null) {
			builder.environment().putAll(this.environment);
		}
		if (dir != null) {
			builder.directory(this.dir);
		}

		process = builder.start();
		final BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
		BufferedReader inReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
		final StringBuffer errMsg = new StringBuffer();

		Thread errThread = new Thread() {
			@Override
			public void run() {
				try {
					String line = errReader.readLine();
					while ((line != null) && !isInterrupted()) {
						errMsg.append(line);
						errMsg.append(System.getProperty("line.separator"));
						line = errReader.readLine();
					}
				} catch (IOException ioe) {
					LogWriter.addLog("INFO","Error reading the error stream {}", ioe.getMessage());
				}
			}
		};
		try {
			errThread.start();
		} catch (IllegalStateException ise) {
		}
		try {
			parseExecResult(inReader);
			exitCode = process.waitFor();
			try {
				errThread.join();
			} catch (InterruptedException ie) {
				LogWriter.addLog("WARN","Interrupted while reading the error stream {}", ie.getMessage());
			}
			completed = true;
			if (exitCode != 0) {
				throw new ExitCodeException(exitCode, errMsg.toString());
			}
		} catch (InterruptedException ie) {
			throw new IOException(ie.toString());
		} finally {
			try {
				inReader.close();
			} catch (IOException ioe) {
				LogWriter.addLog("ERROR","Error while closing the input stream {}", ioe.getMessage());
			}
			if (!completed) {
				errThread.interrupt();
			}
			try {
				errReader.close();
			} catch (IOException ioe) {
				LogWriter.addLog("ERROR","Error while closing the error stream {}", ioe.getMessage());
			}
			process.destroy();
		}
	}
}

/*
 * 使用Shell封装
 */
 class StormScheduler {

	private final static File workDir = new File("/home/admin");

	public static void main(String[] args) {
		//schedule("tlog");
		
		Shell.ShellCommandExecutor executor = new Shell.ShellCommandExecutor(new String[] {"perl D:\\AgentTest\\EXEC_SCRIPT_DIR\\jf_dmrn_ansi_valid_hive.pl"});
		try {
			executor.execute();
		} catch (IOException e) {
			System.out.println("Shell Exception, " + e);
			throw new RuntimeException("StormScheduler error, appName= ", e);
		}
		System.out.println("Shell output: " + executor.getOutput()+executor.getExitCode());
		
	}

	public static void schedule(String appName) {
		System.out.println("Start to execute schedule shell: '/bin/bash storm_scheduler.sh " + appName + "'");
		Shell.ShellCommandExecutor executor = new Shell.ShellCommandExecutor(new String[] { "/bin/bash",
				"storm_scheduler.sh", appName }, workDir);
		try {
			executor.execute();
		} catch (IOException e) {
			System.out.println("Shell Exception, " + e);
			throw new RuntimeException("StormScheduler error, appName= " + appName, e);
		}
		System.out.println("Shell output: " + executor.getOutput()+executor.getExitCode());
	}

}

